--[[
	Ikarus Unit-Frames Addon	
	released under GNU General Public License version 3 (GPLv3) 
	by McGaerty & Sl4ker
	
	contact: mcgaerty@ikarus-systems.net rom@sl4ker.de	
	download: http://rom.curse.com/downloads/rom-addons/details/ikarus-unitframes.aspx
	
	special thanks to Qwox and novayuna for inspiration and stable basics
]]



local ikarus = _G["ikarus"];

--  Provides access to the config frame
ikarus.config.menu = {};

--[[
    ***********************************************************************
    Config Menu
    ***********************************************************************
]]

ikarus.config.menu.isVisible = false;
ikarus.config.menu.isInitialised = false;		
ikarus.config.menu.FRAME = "Ikarus_ConfigFrame";
ikarus.config.menu.CONTENT_FRAME = "Ikarus_ConfigFrameContentFrame";


--[[
    ***********************************************************************
    PAGE HANDLER
    ***********************************************************************
]]

ikarus.config.menu.ConfigPageHandlerClass = ikarus:NewClass(nil);

function ikarus.config.menu.ConfigPageHandlerClass:Init(config, unit, child)	
	self.unit = unit;
	self.child = child;
	
	--  List of handlers
	self.handlers = nil;
	
	self.valid = false;
	
	self:LoadInterface(config);
end;

function ikarus.config.menu.ConfigPageHandlerClass:IsInterfaceLoaded()
	return self.handlers ~= nil;
end;

function ikarus.config.menu.ConfigPageHandlerClass:IsValid()
	return self.valid;
end;

function ikarus.config.menu.ConfigPageHandlerClass:LoadConfig()
	if(self:IsInterfaceLoaded()) then
		for _,handler in ipairs(self.handlers) do
			handler:LoadConfig();
		end;
	end;
end;

function ikarus.config.menu.ConfigPageHandlerClass:SaveConfig()
	if(self:IsInterfaceLoaded()) then
		for _,handler in ipairs(self.handlers) do
			handler:ReadValue();
			handler:SaveConfig();
		end;
	end;
end;

function ikarus.config.menu.ConfigPageHandlerClass:LoadDefaults()
	if(self:IsInterfaceLoaded()) then
		for _,handler in ipairs(self.handlers) do
			handler:LoadDefault();
			handler:DisplayValue();
		end;
	end;
end;

function ikarus.config.menu.ConfigPageHandlerClass:DiscardConfig()
	if(self:IsInterfaceLoaded()) then
		for _,handler in ipairs(self.handlers) do
			handler:Discard();
		end;
	end;
end;

function ikarus.config.menu.ConfigPageHandlerClass:DiscardInterface()
	self.valid = false;
end;

function ikarus.config.menu.ConfigPageHandlerClass:ResetInterface()
	if(self:IsInterfaceLoaded()) then
		for _,handler in ipairs(self.handlers) do
			handler:ResetValue();
			handler:DisplayValue();
		end;
	end;
end;

function ikarus.config.menu.ConfigPageHandlerClass:LoadInterface(config)
	if(ikarus.config.menu:IsInitialised()) then
		self.valid = false;
		self.handlers = nil;
		self.handlers = {};
		
		local handler, manager, frame, frameType, propertyConfig;
		
		--  Config Format:  {"Name", "Template", "Hint","UIComponent",RequiresReloadFlag,OptionalData}
		for index = 2,#config do
			propertyConfig = config[index];
			manager, frame, handler = nil, nil, nil;
			if(type(propertyConfig) == "table") then
				--  Regular property line	
				frameType = ikarus.config.menu.frameTypes[propertyConfig[4]];
				manager = ikarus.config.menu.managers[frameType.MANAGER];
				frame = manager:GetNext();		
				frame.menuIndex = #self.handlers + 1;
				handler = frameType.HANDLER:Create(frame, propertyConfig, self.unit, self.child, frameType.TOPOFFSET, frameType.BOTTOMOFFSET);
			elseif(type(propertyConfig) == "string") then	
				--  Title line
				handler = ikarus.config.menu.TitleHandlerClass:Create(tostring(propertyConfig));
				handler:GetLabel():SetWidth(width);
				frame = handler:GetLabel();
			else
				ikarus.debug:Print("No valid config: "..tostring(self.unit).."/"..tostring(self.child).."/["..index.."]");
			end;
			
			if not(handler and frame) then
				ikarus.debug:Print("Error loading interface for "..tostring(self.unit).."/"..tostring(self.child).."/"..tostring(propertyConfig[1]));
			else
				table.insert(self.handlers, handler);
			end;
		end;
	end;
end;

function ikarus.config.menu.ConfigPageHandlerClass:ShowInterface()
	if(self:IsInterfaceLoaded()) then				
		local frame = getglobal(ikarus.config.menu.FRAME .. "PropertyMainHeader");
		frame:SetText(ikarus.lang.config.units[self.unit].." - "..ikarus.lang.config.children[self.child]);
		
		local left, right;
		local width, scale = frame:GetWidth(), GetUIScale();	

		--  DEBUG we are revalidating all handlers as a little workaround
		if not(self:IsValid() and false) then			
			for index, handler in ipairs(self.handlers) do
				if(handler:GetFrame() ~= nil) then
					handler:GetFrame().menuIndex = index;
				end;
				handler:Revalidate();
			end;
			self.valid = true;
		end;
		
		local height = frame:GetHeight();
		
		--  Build page
		for index, handler in ipairs(self.handlers) do
			handler:LoadBackup();
			left, right = handler:GetMenuComponents(width, scale);
			ikarus.ui:SetAnchor(left, frame, "TOPLEFT","BOTTOMLEFT", 0, index * 40);
			if(right ~= nil) then
				ikarus.ui:SetAnchor(right, frame, "TOPRIGHT", "BOTTOMRIGHT", 0, index * 40);
			end;
			height = height + 40;
		end;
		
		if(height < 300) then height = 300; end;
		
		--  Scroll to top
		getglobal(ikarus.config.menu.FRAME .. "ScrollFrameScrollBar"):SetMinMaxValues(0, height);
		getglobal(ikarus.config.menu.FRAME .. "ScrollFrameScrollBar"):SetValue(0);
	end;
end;

function ikarus.config.menu.ConfigPageHandlerClass:GetHandler(frame)
	return self.handlers[frame.menuIndex];
end;

function ikarus.config.menu.ConfigPageHandlerClass:OnValueChange(frame)
	--ikarus.debug:Print("val change: "..frame:GetName().." - "..frame:GetID());
	if(self:IsValid()) then
		local handler = self:GetHandler(frame);
		if(handler ~= nil) then
			handler:ReadValue();
			handler:SaveConfig();
			
			if(handler:IsBoundProperty()) then
				ikarus:GetDelegate(self.unit):LoadBoundProperties();
			else
				ikarus:GetDelegate(self.unit):LoadConfig();
			end;
		end;
	end;
end;

--[[
    ***********************************************************************
    END PAGE HANDLER
    ***********************************************************************
]]



--[[
    ***********************************************************************
    PROPERTY HANDLER
    ***********************************************************************
]]

ikarus.config.menu.BasicComponentHandlerClass = ikarus:NewClass(nil);

ikarus.config.menu.BasicComponentHandlerClass.OFFSET_X = 0;
ikarus.config.menu.BasicComponentHandlerClass.OFFSET_Y = 20;

function ikarus.config.menu.BasicComponentHandlerClass:Init(frame, config, unit, child, topOffset, bottomOffset)
	self.frame = frame;
	--  Format {"Name", "Template", "Hint","UIComponent",RequiresReloadFlag,OptionalData}
	self.config = config;
	self.label = getglobal(self.frame:GetName() .. "Label");
	self.unit = unit;
	self.child = child;
	self.topOffset = topOffset or 0;
	self.bottomOffset = bottomOffset or 0;
	self.frame.bottomOffset = self.bottomOffset;
	self.property = config[1];
	if(config[2] == nil) then
		self.name = config[1];
	else
		self.name = config[2];
	end;
	self.value = nil;
	self.backup = nil;
	self.isEnabled = true;
	
	self:LoadConfig();
	--self:Revalidate();
end;

function ikarus.config.menu.BasicComponentHandlerClass:IsEnabled()
	return self.isEnabled;
end;

function ikarus.config.menu.BasicComponentHandlerClass:SetEnabled(enabled)
	self.isEnabled = enabled;
end;

function ikarus.config.menu.BasicComponentHandlerClass:LoadLabel()
	if(ikarus.config.menu:IsInitialised() and self.label) then
		self.label:SetText(tostring(ikarus.lang.config.properties[self.name]));
	end;
end;

function ikarus.config.menu.BasicComponentHandlerClass:LoadBackup()
	if(ikarus.config.menu:IsInitialised()) then
		self.backup = ikarus.profile[self.unit][self.child][self.property];
	end;
end;

function ikarus.config.menu.BasicComponentHandlerClass:LoadConfig()
	if(ikarus.config.menu:IsInitialised()) then
		self.value = ikarus.profile[self.unit][self.child][self.property];
	end;
end;

function ikarus.config.menu.BasicComponentHandlerClass:SaveConfig()
	if(ikarus.config.menu:IsInitialised()) then
		ikarus.profile[self.unit][self.child][self.property] = self.value;
	end;
end;

function ikarus.config.menu.BasicComponentHandlerClass:LoadDefault()
	if(ikarus.config.menu:IsInitialised()) then
		self.value = ikarus.config.defaults[self.unit][self.child][self.property];
	end;
end;

function ikarus.config.menu.BasicComponentHandlerClass:ResetValue()
	self.value = self.backup;
end;

function ikarus.config.menu.BasicComponentHandlerClass:GetValue()
	return self.value;
end;

function ikarus.config.menu.BasicComponentHandlerClass:SetValue(value)
	self.value = value;
end;

function ikarus.config.menu.BasicComponentHandlerClass:GetUnit()
	return self.unit;
end;

function ikarus.config.menu.BasicComponentHandlerClass:GetChild()
	return self.child;
end;

function ikarus.config.menu.BasicComponentHandlerClass:GetProperty()
	return self.property;
end;

function ikarus.config.menu.BasicComponentHandlerClass:GetConfig()
	return self.config;
end;

function ikarus.config.menu.BasicComponentHandlerClass:RequiresReload()
	return self.config[5] == true;
end;

function ikarus.config.menu.BasicComponentHandlerClass:GetFrame()
	return self.frame;
end;

function ikarus.config.menu.BasicComponentHandlerClass:GetLabel()
	return self.label;
end;

function ikarus.config.menu.BasicComponentHandlerClass:GetSecondFrame()
	return self.frame2;
end;

function ikarus.config.menu.BasicComponentHandlerClass:IsLoaded()
	if(self.value ~= nil) then
		return true;
	else
		return false;
	end;
end;

function ikarus.config.menu.BasicComponentHandlerClass:IsBoundProperty()
	return not self.config[5];
end;

function ikarus.config.menu.BasicComponentHandlerClass:GetMenuComponents(width, scale)
	--ikarus.debug:Print("append: "..tostring(leftParent:GetName()).."/"..tostring(rightParent:GetName()));
	
	--  Refresh UI content
	self:LoadLabel();
	self:LoadConfig();
	self:DisplayValue();
	
	self.label:Show();
	self.frame:Show();
	
	return self.label, self.frame;
end;

--  Displays the currently cached value in the menu
function ikarus.config.menu.BasicComponentHandlerClass:DisplayValue()
end;

--  Reads in the new value resulting from user interaction
function ikarus.config.menu.BasicComponentHandlerClass:ReadValue()
	self.value = nil;
end;

--  Performs initialisation of the underlying components, e.g. set title, min/max values etc
function ikarus.config.menu.BasicComponentHandlerClass:Revalidate()	
end;

--  CHECKBOX

ikarus.config.menu.CheckBoxHandlerClass = ikarus:NewClass(ikarus.config.menu.BasicComponentHandlerClass);

function ikarus.config.menu.CheckBoxHandlerClass:DisplayValue()
	self.frame:SetChecked(self.value);
end;

function ikarus.config.menu.CheckBoxHandlerClass:ReadValue()
	self.value = self.frame:IsChecked() == true;
end;

--  TEXTFIELD

ikarus.config.menu.TextFieldHandlerClass = ikarus:NewClass(ikarus.config.menu.BasicComponentHandlerClass);

function ikarus.config.menu.TextFieldHandlerClass:DisplayValue()
	self.frame:SetText(tostring(self.value));
end;

function ikarus.config.menu.TextFieldHandlerClass:ReadValue()
	self.value = tostring(self.frame:GetText());
end;

--  NUMBERFIELD

ikarus.config.menu.NumberFieldHandlerClass = ikarus:NewClass(ikarus.config.menu.BasicComponentHandlerClass);

function ikarus.config.menu.NumberFieldHandlerClass:DisplayValue()
	self.frame:SetText(tostring(self.value));
end;

function ikarus.config.menu.NumberFieldHandlerClass:ReadValue()
	local val = tonumber(self.frame:GetText());
	if(val ~= nil) then
		self.frame:SetText(tostring(self.value));
	else
		self.value = val;
	end;
end;

--  SLIDER

ikarus.config.menu.SliderHandlerClass = ikarus:NewClass(ikarus.config.menu.BasicComponentHandlerClass);

ikarus.config.menu.SliderHandlerClass.ACCURACY = 100;

function ikarus.config.menu.SliderHandlerClass:Revalidate()	
	--  Format {"Name", "Template", "Hint","UIComponent",RequiresReloadFlag,*MIN, *MAX, STEP_LENGTH, LEFT_LABLE, RIGHT_LABLE}
	
	self.minVal = tonumber(ikarus.config.menu:ReadValue(self.config[6]));
	self.maxVal = tonumber(ikarus.config.menu:ReadValue(self.config[7]));
	
	if(self.maxVal <= self.minVal) then
		self.minVal = -self.minVal;
	end;
	
	if((self.maxVal - self.minVal) >= 10) then 
		self.frame:SetValueStepMode("INT");
		self.minVal = math.floor(self.minVal);
		self.maxVal = math.floor(self.maxVal);
	else
		self.frame:SetValueStepMode("FLOAT");
	end;
	
	if(self.config[9]) then
		getglobal(self.frame:GetName() .. "Low"):SetText(ikarus.lang.config.controls[self.config[9]]);
	else
		getglobal(self.frame:GetName() .. "Low"):SetText(tostring(self.minVal));
	end;
	if(self.config[10]) then
		getglobal(self.frame:GetName() .. "High"):SetText(ikarus.lang.config.controls[self.config[10]]);
	else
		getglobal(self.frame:GetName() .. "High"):SetText(tostring(self.maxVal));
	end;
	self.frame:SetMinMaxValues(self.minVal, self.maxVal);
end;

function ikarus.config.menu.SliderHandlerClass:DisplayValue()
	self.frame:SetValue(tonumber(self.value));
	if(self.frame:GetValueStepMode() == "INT") then
		getglobal(self.frame:GetName() .. "Value"):SetText(tostring(math.floor(self.value)));
	else
		getglobal(self.frame:GetName() .. "Value"):SetText(string.format("%1.2f", self.value));
	end;
end;

function ikarus.config.menu.SliderHandlerClass:ReadValue()
	if(self.frame:GetValueStepMode() == "INT") then
		self.value = math.floor(self.frame:GetValue());
	else
		self.value = self.frame:GetValue();
	end;
	self:DisplayValue();
end;

--  COLORPICKER

ikarus.config.menu.ColorPickerHandlerClass = ikarus:NewClass(ikarus.config.menu.BasicComponentHandlerClass);

function ikarus.config.menu.ColorPickerHandlerClass:Revalidate()	
	getglobal(self.frame:GetName() .. "Button"):SetText(ikarus.lang.config.controls.SELECT);
end;

function ikarus.config.menu.ColorPickerHandlerClass:DisplayValue()
	getglobal(self.frame:GetName() .. "ColorTexture"):SetColor(unpackCol(self.value));
end;

function ikarus.config.menu.ColorPickerHandlerClass:ReadValue()
	--local col_r,col_g,col_b,col_a = getglobal(self.frame:GetName() .. "ColorTexture"):GetColor();
	--self.value = {r = col_r, g = col_g, b = col_b, a = col_a};
	--  ATTENTION: colorpicker support directly sets the color of our preview texture object, so no need to revalidate
end;

--  COMBOBOX

ikarus.config.menu.ComboBoxHandlerClass = ikarus:NewClass(ikarus.config.menu.BasicComponentHandlerClass);

function ikarus.config.menu.ComboBoxHandlerClass:Revalidate()	
	--  Format {"Name", "Template", "Hint","UIComponent",RequiresReloadFlag,*OPTIONS,LOCALIZE}
	local frame = getglobal(self.frame:GetName() .. "DropDown");
	frame.options = ikarus.config.menu:ReadValue(self.config[6]);
	frame.localize = self.config[7] or false;
	UIDropDownMenu_SetWidth(frame, 160);
	UIDropDownMenu_Initialize(frame, ikarus.config.menu.ShowDropDown);
end;

function ikarus.config.menu.ComboBoxHandlerClass:DisplayValue()
	local frame = getglobal(self.frame:GetName() .. "DropDown");
	UIDropDownMenu_Initialize(frame, ikarus.config.menu.ShowDropDown);
	--UIDropDownMenu_SetSelectedValue(frame, self.value);
end;

function ikarus.config.menu.ComboBoxHandlerClass:ReadValue()
	local frame = getglobal(self.frame:GetName() .. "DropDown");
	self.value = UIDropDownMenu_GetSelectedValue(frame);
end;

--  INFO

ikarus.config.menu.TitleHandlerClass = ikarus:NewClass(ikarus.config.menu.BasicComponentHandlerClass);

function ikarus.config.menu.TitleHandlerClass:Init(title)	
	self.label = ikarus.config.menu.managers.header:GetNext();
	self.title = title;
end;

function ikarus.config.menu.TitleHandlerClass:LoadLabel()
	if(ikarus.config.menu:IsInitialised() and self.label) then
		self:Revalidate();
	end;
end;

function ikarus.config.menu.TitleHandlerClass:LoadBackup()
end;

function ikarus.config.menu.TitleHandlerClass:LoadConfig()
end;

function ikarus.config.menu.TitleHandlerClass:SaveConfig()
end;

function ikarus.config.menu.TitleHandlerClass:LoadDefault()
end;

function ikarus.config.menu.TitleHandlerClass:Revalidate()
	self.label:SetText(tostring(ikarus.lang.config.titles[self.title]));
end;

function ikarus.config.menu.TitleHandlerClass:GetMenuComponents(width, scale)
	self:LoadLabel();
	--self.label:SetWidth(self.label:GetTextWidth() + 10);
	self.label:SetWidth(width);
	self.label:Show();
	
	return self.label;
end;

--  INFO

ikarus.config.menu.TextHandlerClass = ikarus:NewClass(ikarus.config.menu.TitleHandlerClass);

function ikarus.config.menu.TextHandlerClass:Init(config)	
	self.label = ikarus.config.menu.managers.text:GetNext();
	self.blocks = {};	
end;

function ikarus.config.menu.TextHandlerClass:LoadLabel()
	if(ikarus.config.menu:IsInitialised() and self.label) then
		self:Revalidate();
	end;
end;

function ikarus.config.menu.TextHandlerClass:Revalidate()
	self.label:SetText(tostring(ikarus.lang.config.titles[self.title]));
end;

--  BUTTON

ikarus.config.menu.ButtonHandlerClass = ikarus:NewClass(ikarus.config.menu.BasicComponentHandlerClass);

function ikarus.config.menu.ButtonHandlerClass:Init(frame, config, unit, child)
	self.frame = frame;
	--  Format {"Name", "Template", "Hint","UIComponent",RequiresReloadFlag,OptionalData}
	self.config = config;
	self.label = getglobal(self.frame:GetName() .. "Label");
	self.unit = unit;
	self.child = child;
	self.property = config[1];
	self.frame.event = self.property;
	if(config[2] == nil) then
		self.name = config[1];
	else
		self.name = config[2];
	end;
	self.value = nil;
	self.backup = nil;
	self.isEnabled = true;
	
	self:LoadConfig();
	--self:Revalidate();
end;

function ikarus.config.menu.ButtonHandlerClass:Revalidate()	
	self.frame:SetText(ikarus.lang.config.controls.TOGGLE);
end;

--[[
    ***********************************************************************
    END PROPERTY HANDLER
    ***********************************************************************
]]




--[[
    ***********************************************************************
    COMPONENT MANAGER
    ***********************************************************************
]]
ikarus.config.menu.ComponentManagerClass = ikarus:NewClass(nil);

function ikarus.config.menu.ComponentManagerClass:Init(name, frameType, first, last, initFunc)
	self.name = name;
	self.frameType = frameType;
	self.first = first;
	self.last = last;
	self.count = first - 1;
	self.initFunc = initFunc;
	self:Clear();
end;

--  Returns the next available frame, the frameType field and the current count value
function ikarus.config.menu.ComponentManagerClass:GetNext()
	if(self.count < self.last) then
		self.count = self.count + 1;
		local frame = getglobal(self.name .. tostring(self.count));
		if(self.initFunc) then
			self:initFunc(frame);
		end;
		return frame, self.frameType, self.count;
	end;
end;

function ikarus.config.menu.ComponentManagerClass:GetCount()
	return self.count;
end;

function ikarus.config.menu.ComponentManagerClass:GetLastIndex()
	return self.last;
end;

function ikarus.config.menu.ComponentManagerClass:GetFirstIndex()
	return self.first;
end;

function ikarus.config.menu.ComponentManagerClass:GetName()
	return self.name;
end;

function ikarus.config.menu.ComponentManagerClass:GetFrameType()
	return self.frameType;
end;

function ikarus.config.menu.ComponentManagerClass:Clear()
	local frame;
	for index = self.first, self.last do
		frame = getglobal(self.name .. tostring(index));
		if(frame) then frame:Hide(); end;
	end;
	self.count = self.first - 1;
end;

--[[
    ***********************************************************************
    END COMPONENT MANAGER
    ***********************************************************************
]]

--  Maps UIComponent names to managers
ikarus.config.menu.frameTypes = {
    ["CHECKBOX"] = {
		["MANAGER"] = "checkbox", 
		["HANDLER"] = ikarus.config.menu.CheckBoxHandlerClass
	},
    ["SLIDER"] = {
		["MANAGER"] = "slider", 
		["HANDLER"] = ikarus.config.menu.SliderHandlerClass,
		["TOPOFFSET"] = 14,
		["BOTTOMOFFSET"] = 10
	},
    ["TEXTFIELD"] = {
		["MANAGER"] = "textfield", 
		["HANDLER"] = ikarus.config.menu.TextFieldHandlerClass
	},
    ["NUMBERFIELD"] = {
		["MANAGER"] = "textfield", 
		["HANDLER"] = ikarus.config.menu.NumberFieldHandlerClass
	},
    ["COLORPICKER"] = {
		["MANAGER"] = "colorpicker", 
		["HANDLER"] = ikarus.config.menu.ColorPickerHandlerClass
	},
    ["COMBOBOX"] = {
		["MANAGER"] = "combobox", 
		["HANDLER"] = ikarus.config.menu.ComboBoxHandlerClass
	},
    ["TEXT"] = {
		["MANAGER"] = "text", 
		["HANDLER"] = ikarus.config.menu.TextHandlerClass
	},
    ["BUTTON"] = {
		["MANAGER"] = "button", 
		["HANDLER"] = ikarus.config.menu.ButtonHandlerClass
	}
};


function ikarus.config.menu:IsVisible()
	--return self.isVisible == true;
	return getglobal(self.FRAME):IsVisible();
end;

function ikarus.config.menu:IsInitialised()
	return self.isInitialised == true;
end;

function ikarus.config.menu:Initialise()
	if not(self:IsInitialised()) and ikarus.config:IsLoaded() then
	
		--  WORKAROUND
		RunScript("SYS_DisplaySettings_Frame:Show()");		
		Ikarus_EventFrame.configX, Ikarus_EventFrame.configY = SYS_DisplaySettings_Frame:GetPos();
		RunScript("SYS_DisplaySettings_Frame:SetPos(-"..SYS_DisplaySettings_Frame:GetWidth()..",0)");
		Ikarus_EventFrame.delay = 1;
	
	
		--  List of component managers
		self.managers = {};
		
		--  Current unit and child
		self.unit = "global";
		self.unitIndex = 1;
		self.childIndex = 2;
		
		--  List of page handlers. Maps "unit_child" to a handler
		self.handlers = {};
		
		--  Load managers
		self.managers["slider"] = self.ComponentManagerClass:Create("P_Slider", "SLIDER", 1, 30);
		self.managers["checkbox"] = self.ComponentManagerClass:Create("P_CheckButton", "CHECKBOX", 1, 30);
		self.managers["colorpicker"] = self.ComponentManagerClass:Create("P_ColorPicker", "COLORPICKER", 1, 20);
		self.managers["textfield"] = self.ComponentManagerClass:Create("P_EditBox", "TEXTFIELD", 1, 20);
		self.managers["combobox"] = self.ComponentManagerClass:Create("P_ComboBox", "COMBOBOX", 1, 20);
		self.managers["header"] = self.ComponentManagerClass:Create("P_Header", "INFO", 1, 15);
		self.managers["text"] = self.ComponentManagerClass:Create("P_Text", "TEXT", 1, 10);
		self.managers["button"] = self.ComponentManagerClass:Create("P_Button", "BUTTON", 1, 20);
		
		--  Some UI stuff
		UIDropDownMenu_SetWidth(getglobal(self.FRAME .. "UnitDropDown"), 95);
		UIDropDownMenu_SetWidth(getglobal(self.FRAME .. "ChildDropDown"), 95);
		
		
		self.isInitialised = true;
	end;
end;


function ikarus.config.menu:ClearComponentManagers()
	if(self:IsInitialised()) then
		self.managers["slider"]:Clear();
		self.managers["checkbox"]:Clear();
		self.managers["colorpicker"]:Clear();
		self.managers["textfield"]:Clear();
		self.managers["combobox"]:Clear();
		self.managers["header"]:Clear();	
		self.managers["text"]:Clear();		
		self.managers["button"]:Clear();		
	end;
end;

function ikarus.config.menu:ShowConfigFrame(unit, child)
	if not(self:IsVisible()) then
		if not(self:IsInitialised()) then
			self:Initialise();
		end;
		
		--  Clean up
		self:HideUtilities();
		
		--  Load interface values (see the interface table for detail)
		self:UpdateInterfaceValues();
		
		--  Display header/footer
		getglobal(self.FRAME .. "Header"):SetText(ikarus.lang.config.header);
		getglobal(self.FRAME .. "Version"):SetText(ikarus.lang.config.footer .." ".. ikarus.utils:VersionString());
		
		--  Control buttons
		getglobal(self.FRAME .. "DefaultButton"):SetText(ikarus.lang.config.controls.DEFAULT);
		getglobal(self.FRAME .. "CancelButton"):SetText(ikarus.lang.config.controls.CANCEL);
		getglobal(self.FRAME .. "OkButton"):SetText(ikarus.lang.config.controls.OK);
		getglobal(self.FRAME .. "ApplyButton"):SetText(ikarus.lang.config.controls.APPLY);
		
		--  DropDown menus
		getglobal(self.FRAME .. "UnitDropDownLabel"):SetText(ikarus.lang.config.unittitle);
		getglobal(self.FRAME .. "ChildDropDownLabel"):SetText(ikarus.lang.config.childtitle);
		
		self.isVisible = true;	
		ikarus.ui:SetLocked(true);		
		getglobal(self.FRAME):Show();
			
		local unitDropDown, childDropDown = getglobal(self.FRAME .. "UnitDropDown"), getglobal(self.FRAME .. "ChildDropDown");
		UIDropDownMenu_Initialize(unitDropDown, ikarus.config.menu.UnitDropDownShow);
		UIDropDownMenu_SetSelectedID(unitDropDown, self.unitIndex);

		UIDropDownMenu_Initialize(childDropDown, ikarus.config.menu.ChildDropDownShow);
		UIDropDownMenu_SetSelectedID(childDropDown, self.childIndex - 1);
		
		self:ShowChildDialog();
	end;
end;

function ikarus.config.menu:ShowChildDialog()
	--  Clean up
	self:HideUtilities();
	
	if(self:IsVisible()) then		
		local config = ikarus.config.interface[self.unitIndex][self.childIndex];
		
		self.unit = ikarus.config.interface[self.unitIndex][1];
		self.child = config[1];
	
		--  Free data
		if(self.activeHandler) then
			self.activeHandler:DiscardInterface();
			self.activeHandler = nil;
		end;	
		
		--  Reload interface data
		self:UpdateInterfaceValues();
		
		--  Release all property related components
		self:ClearComponentManagers();				
		
		--  Check for handler and load interface
		local key = string.upper(self.unit .."_".. self.child);
		if (self.handlers[key] == nil) then
			self.handlers[key] = self.ConfigPageHandlerClass:Create(config, self.unit, self.child);
		end;
		self.activeHandler = self.handlers[key];
		
		--  Dummy support
		--ikarus:GetDelegate(self.unit):SetDummy(true);
		--ikarus:SetDummyState(true);
		
		self.activeHandler:ShowInterface();		
	end;
end;

function ikarus.config.menu:HideConfigFrame()
	getglobal(self.FRAME):Hide();
	self:HideUtilities();
	self:ClearMenuState();
end;

function ikarus.config.menu:ClearMenuState()
	if(self.activeHandler) then
		self.activeHandler:DiscardInterface()
	end;
	self.isVisible = false;
	ikarus.ui:SetLocked(false);
	ikarus:SetDummyState(false);
end;

function ikarus.config.menu:HideUtilities()
	ColorPickerFrame:Hide();
	ikarus.config.utilities.colorpicker = nil;
	CloseDropDownMenus();
end;

ikarus.config.interface.ALIGNMENTS = {
	"TOP", "TOPLEFT", "LEFT", "BOTTOMLEFT", "BOTTOM", "BOTTOMRIGHT", "RIGHT", "TOPRIGHT"
};

ikarus.config.interface.SIMPLE_ALIGNMENTS = {
	"TOP", "LEFT", "BOTTOM", "RIGHT"
};

ikarus.config.interface.ORIENTATIONS = {
	"HORIZONTAL", "VERTICAL"
};

ikarus.config.interface.BAR_TEXTURES ={
	"Healbot", "Smooth","Glamour","Glamour3", "Glamour6",
	"Glamour7","Aluminium","Cloud","Dabs","DarkBottom",
	"Fifths","Flat","Fourths","Minimalist","BantoBar",
	"Charcoal","Glaze","Gloss","Graphite","LiteStep",
	"Lyfe","MelliDarkRough","Otravi","Perl2","Pill",
	"Rocks","Runes","Striped","Water","Wisps",
	"Tube","Steel"
};

ikarus.config.interface.FONTS =	{
	"Default"
};

ikarus.config.interface.NUMBER_FORMATS = {
	"UNFORMATTED", "SHORTENED"
};

ikarus.config.interface.COLORIZERS = {
	"NONE", "DIFFICULTY", "RELATION", "BLOODBAR", "CLASS", "WOW_CLASS"
};

ikarus.config.interface.LANGUAGES = {
	"ENEU", "DE", "FR"
};

ikarus.config.interface.PROFILES = {};

function ikarus.config.menu:UpdateInterfaceValues()
	--[[
	List of available config.interface values
		MAX_OFFSET_X
		MAX_OFFSET_Y
		BAR_TEXTURES
		FONTS
		MIN_FONT_SIZE
		MAX_FONT_SIZE
		ALIGNMENTS
		SIMPLE_ALIGNMENTS
		ORIENTATIONS
		NUMBER_FORMATS
		COLORIZERS
		LANGUAGES
	]]
	
	--ikarus.config.interface.MAX_OFFSET_X 	=	GetScreenWidth();
	--ikarus.config.interface.MAX_OFFSET_Y 	=	GetScreenHeight();
	
	--  WORKAROUND
	local index = UIDropDownMenu_GetSelectedID(SYS_DisplaySettings_ResolutionDropDown);
	ikarus.config.interface.MAX_OFFSET_X 	=	SYS_DispSet_GetDispWidth(index - 1);
	ikarus.config.interface.MAX_OFFSET_Y 	=	SYS_DispSet_GetDispHeight(index - 1);
	
	ikarus.config.interface.PROFILES = {};
	for name,profile in pairs(Ikarus_VARS) do
		if(name ~= "PROFILES" and type(profile) == "table") then
			table.insert(ikarus.config.interface.PROFILES, name);
		end;
	end;
	
	ikarus.config.interface.MIN_FONT_SIZE 	=	6;
	ikarus.config.interface.MAX_FONT_SIZE 	=	20;
end;

function ikarus.config.menu:ReadValue(value, buffer)
	--ikarus.debug:Print("initial value: "..tostring(value).." "..type(value));
	if(type(value) == "string") then
		--  Check for links
		if(string.sub(value,1,2) == "##") then
			--  Resolve config link
			local item = ikarus.config;
			for key in string.gmatch(string.sub(value,3), "([^%.]+)") do
				item = item[key];
		    end;
			
			if(type(item) == "function") then
				value = item();
			else
				value = item;
			end;
		elseif(string.sub(value,1,2) == "$$") then
			--  Call frame function
			local index = string.find(value, ".", 1, true);
			local frame = getglobal(string.sub(value,3,index-1));
			local func = string.lower(string.sub(value,index+1));
			
			--  Check for the most common functions
			if(func == "getheight") then
				value = frame:GetHeight();
			elseif(func == "getwidth") then
				value = frame:GetWidth();
			elseif(func == "getalpha") then
				value = frame:GetAlpha();
			end;
		end;
	end;
	if(buffer) then
		buffer.value = value;
	end;
	--ikarus.debug:Print("final value: "..tostring(value).." "..type(value));
	return value;
end;


--[[
    ***********************************************************************
    Event Handling
    ***********************************************************************
]]

function ikarus.config.menu:OnValueChange(frame)
	if(self:IsVisible() and self.activeHandler) then
		self.activeHandler:OnValueChange(frame);
	end;
end;

--  Display unit dropdown
function ikarus.config.menu.UnitDropDownShow()
	local info, unitConf;
	for index = 1,#ikarus.config.interface do
		unitConf = ikarus.config.interface[index];
	    info = {};
	    info.text = ikarus.lang.config.units[unitConf[1]];
	    info.func = ikarus.config.menu.OnUnitSelect;
	    UIDropDownMenu_AddButton(info);		
	end;
end;

--  Display child dropdown
function ikarus.config.menu.ChildDropDownShow()
	local info, childConf;
	for index = 2,#ikarus.config.interface[ikarus.config.menu.unitIndex] do
		childConf = ikarus.config.interface[ikarus.config.menu.unitIndex][index];
	    info = {};
	    info.text = ikarus.lang.config.children[childConf[1]];
	    info.func = ikarus.config.menu.OnChildSelect;
	    UIDropDownMenu_AddButton(info);		
	end;
end;

function ikarus.config.menu.OnUnitSelect(button)
	local index = button:GetID();
	if(ikarus.config.menu:IsVisible() and index ~= ikarus.config.menu.unitIndex) then
		UIDropDownMenu_SetSelectedID(getglobal(ikarus.config.menu.FRAME .. "UnitDropDown"), index);
		ikarus.config.menu.unitIndex = index;
		ikarus.config.menu.childIndex = 2;
		ikarus.config.menu.child = nil;
		UIDropDownMenu_Initialize(getglobal(ikarus.config.menu.FRAME .. "ChildDropDown"), ikarus.config.menu.ChildDropDownShow);
		UIDropDownMenu_SetSelectedID(getglobal(ikarus.config.menu.FRAME .. "ChildDropDown"), 1);
		ikarus.config.menu:ShowChildDialog();
	end;
end;

function ikarus.config.menu.OnChildSelect(button)
	local index = button:GetID();
	if(ikarus.config.menu:IsVisible()) then
		UIDropDownMenu_SetSelectedID(getglobal(ikarus.config.menu.FRAME .. "ChildDropDown"), index);
		ikarus.config.menu.childIndex = index + 1;
		ikarus.config.menu.child = nil;
		ikarus.config.menu:ShowChildDialog();
	end;
end;

--  Color picker utilities

function ikarus.config.menu:OpenColorSelect(button)
	if(self:IsVisible() and ikarus.config.menu.activeHandler) then
		--ikarus.debug:Print(button:GetName().." "..button:GetParent():GetID());
		local handler = ikarus.config.menu.activeHandler:GetHandler(button:GetParent());
		local color = handler:GetValue();
		ikarus.config.utilities.colorpicker = nil;
		ikarus.config.utilities.colorpicker = {};
		ikarus.config.utilities.colorpicker.backupColor = color;
		ikarus.config.utilities.colorpicker.handler = handler;
		
		local info = {};
		info.r = color.r;
		info.g = color.g;
		info.b = color.b;
		info.a = color.a;
		info.alphaMode = 1;
		info.titleText = ikarus.lang.config.properties[handler:GetProperty()];
		info.callbackFuncOkay   = ikarus.config.menu.OnColorPickerOkay;
		info.callbackFuncUpdate = ikarus.config.menu.OnColorPickerUpdate;
		info.callbackFuncCancel = ikarus.config.menu.OnColorPickerCancel;
		
		OpenColorPickerFrameEx(info);
	end;
end;

function ikarus.config.menu.OnColorPickerUpdate()
	if(ikarus.config.menu:IsVisible() and ikarus.config.utilities.colorpicker) then		
		--  Save current value and tell handler to reload
		local handler = ikarus.config.utilities.colorpicker.handler;
		getglobal(handler:GetFrame():GetName() .. "ColorTexture"):SetColor(
			ColorPickerFrame.r, ColorPickerFrame.g, ColorPickerFrame.b, ColorPickerFrame.a);
		handler.value = {r = ColorPickerFrame.r; g = ColorPickerFrame.g; b = ColorPickerFrame.b; a = ColorPickerFrame.a};
		
		ikarus.config.menu.activeHandler:OnValueChange(handler:GetFrame());
	else
		ikarus.config.menu:HideUtilities();
	end;
end;

function ikarus.config.menu.OnColorPickerOkay()
	--  Just clean up
	ikarus.config.menu:HideUtilities();
end;

function ikarus.config.menu.OnColorPickerCancel()
	if(ikarus.config.menu:IsVisible() and ikarus.config.utilities.colorpicker) then
		--  Restore backup color and tell handler to reload
		local handler = ikarus.config.utilities.colorpicker.handler;
		local color = ikarus.config.utilities.colorpicker.backupColor;
		getglobal(handler:GetFrame():GetName() .. "ColorTexture"):SetColor(color.r, color.g, color.b, color.a);
		
		ikarus.config.menu.activeHandler:OnValueChange(handler:GetFrame());
	end;
	ikarus.config.menu:HideUtilities();
end;

--  General drop down menu utilities

function ikarus.config.menu.ShowDropDown(frame)
	--ikarus.debug:Print(frame:GetName().."/"..frame:GetParent():GetName());
	if(ikarus.config.menu:IsVisible() and ikarus.config.menu.activeHandler) then
		local handler = ikarus.config.menu.activeHandler:GetHandler(frame:GetParent());
		--handler:LoadConfig();
		--  Format {"Name", "Template", "Hint","UIComponent",RequiresReloadFlag,*OPTIONS,LOCALIZE}
		local info;
		local options = frame.options;
		local localize = frame.localize;
		
		
		for index = 1,#options do
			info = {};
			if(localize == true) then
				info.text = tostring(ikarus.lang.config.controls[options[index]]);
			else
				info.text = tostring(options[index]);
			end;
			info.owner = handler:GetFrame();
			info.value = tostring(options[index]);
			info.func = ikarus.config.menu.OnDropDownSelect;
			UIDropDownMenu_AddButton(info);
		end;	
		
		UIDropDownMenu_SetSelectedValue(frame, tostring(handler:GetValue()));
				
		--  WORKAROUND
		--  BUG: DropDownList objects seem to remain stuck at their first location on screen when inside a scrollframe
		--  could not figure out what was wrong, so we manualy set the desired location relative to the current frame
		local listFrame = getglobal("DropDownList1");
		local scrollBar = getglobal("Ikarus_ConfigFrameScrollFrameScrollBar");
		listFrame.parent = frame;
		ikarus.ui:SetAnchor(listFrame, getglobal(frame:GetName().."Button"), "TOPRIGHT", "BOTTOMRIGHT", 1, -scrollBar:GetValue());
	end;
end;

function ikarus.config.menu.OnDropDownSelect(button)
	if(ikarus.config.menu:IsVisible() and ikarus.config.menu.activeHandler) then
		--  Set selected value on dropdown menu and tell handler to reload
		local frame = getglobal(UIDROPDOWNMENU_OPEN_MENU);		
		UIDropDownMenu_SetSelectedValue(frame, button.value);
		
		--  dropdown menu is nested component
		ikarus.config.menu.activeHandler:OnValueChange(frame:GetParent());
	else
		ikarus.config.menu:HideUtilities();
	end;
end;

function ikarus.config.menu:ControlButtonClicked(button, operation)
	if(self:IsVisible()) then
		local close, reload = false;
		if("CANCEL" == operation) then
			self.activeHandler:ResetInterface();
			close = true;
		elseif("OK" == operation) then
			close = true;
		elseif("APPLY" == operation) then
			reload = true;
		elseif("DEFAULT" == operation) then
			self.activeHandler:LoadDefaults();
		end;
		self.activeHandler:SaveConfig();
		if(reload == true) then
			--self.activeHandler:LoadConfig();
		end;
		--self.activeHandler:ShowInterface();
		ikarus.config:SaveProfile();
		if(close == true) then
			self:HideConfigFrame();
		end;
		ikarus:GetDelegate(self.activeHandler.unit):LoadConfig();
	end;
end;

function ikarus.config.menu:OnMenuButtonClick(button)
	local event = button.event;
	if(event == "DUMMY_STATE" and self.activeHandler) then
		local delegate = ikarus:GetDelegate(self.activeHandler.unit);
		delegate:SetDummy(not delegate:IsDummy());
	end;
end;
